package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huifu.adapay.Adapay;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.Member;
import com.huifu.adapay.model.MerConfig;
import com.huifu.adapay.model.SettleAccount;
import com.tbit.uqbike.constant.BrandRemoteConfigConstant;
import com.tbit.uqbike.constant.OperaPswConstant;
import com.tbit.uqbike.constant.ServiceUrlConstant;
import com.tbit.uqbike.constant.SubAccountConstant;
import com.tbit.uqbike.enums.AdapayCashType;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.SubAccountDTO;
import com.tbit.uqbike.object.pojo.dto.SubAccountMerchantsDTO;
import com.tbit.uqbike.object.pojo.dto.SubAccountRatioDTO;
import com.tbit.uqbike.object.pojo.dto.SubAccountRatioDetailDTO;
import com.tbit.uqbike.object.pojo.vo.*;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.common.entity.view.PageResult;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.quartz.SubAccountQuartz;
import com.tbit.uqbike.service.business.BrandRemoteConfigService;
import com.tbit.uqbike.service.business.SubAccountService;
import com.tbit.uqbike.webmanager.business.machinegroup.object.MachineGroup;
import com.tbit.uqbike.webmanager.business.machinegroup.object.vo.MachineGroupVo;
import com.tbit.uqbike.webmanager.business.machinegroup.service.MachineGroupService;
import com.tbit.uqbike.webmanager.business.userdivide.dao.core.UserDivideDao;
import com.tbit.uqbike.webmanager.business.userdivide.object.SubAccountRatio;
import com.tbit.uqbike.webmanager.dao.core.AdaPayConfigDao;
import com.tbit.uqbike.webmanager.dao.core.BrandRemoteConfigDao;
import com.tbit.uqbike.webmanager.dao.core.SubAccountDao;
import com.tbit.uqbike.webmanager.dao.log.SubAccountLogDao;
import com.tbit.uqbike.webmanager.util.MD5PasswordUtil;
import com.tbit.uqbike.webmanager.util.adaPay.AdaPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 分账管理接口实现类
 *
 * @Author:BUGTian
 * @DATE: 2022/5/23
 */
@Service
@Slf4j
public class SubAccountServiceImpl implements SubAccountService {

    @Autowired
    private SubAccountDao subAccountDao;

    @Autowired
    private AdaPayConfigDao adaPayConfigDao;

    @Autowired
    private SubAccountQuartz subAccountQuartz;

    @Autowired
    private SubAccountLogDao subAccountLogDao;

    @Autowired
    private BrandRemoteConfigDao brandRemoteConfigDao;

    @Autowired
    private MachineGroupService machineGroupService;

    @Autowired
    private UserDivideDao userDivideDao;

    @Autowired
    private BrandRemoteConfigService brandRemoteConfigService;

    @Override
    //@Transactional(rollbackFor = Exception.class)
    public Result createMember(SubAccountDTO subAccountDTO) {
        if (subAccountDTO.getAutoRemark() != null && subAccountDTO.getAutoRemark().length() > 30) {
            return Result.error("自动提现备注长度不能超过三十");
        }
        checkLength(subAccountDTO);
        //校验参数
        check(subAccountDTO);
        //获取汇付款支付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getInfoByAccountId(subAccountDTO.getAccountId());
        try {
            AdaPayUtil.initConfig(adaPayConfig);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("初始化配置失败，请检查汇付配置是否有误");
        }
        SubAccount subAccount = new SubAccount();
        BeanUtils.copyProperties(subAccountDTO, subAccount);
        //状态设为审核中，余额设为0
        subAccount.setState(SubAccountConstant.REVIEW).setBalance(0).setAddTime(new Date()).setMemberId("");
        subAccountDao.insert(subAccount);
        //创建memberId
        Integer subAccountId = subAccount.getSubAccountId();
        String memberId = String.format("%s_%s_%s_%s", SubAccountConstant.MEMBER_ID_PRE, subAccount.getAccountId(), subAccountId, System.currentTimeMillis());
        subAccount.setMemberId(memberId);
        //更新memberId
        subAccountDao.updateMemberId(subAccountId, memberId);
        //创建聚合支付用户
        boolean flag;
        String msg;
        switch (subAccount.getBankAccountType()) {
            case 1:
                //对公，创建企业用户对象，同时自动创建结算用户
                try {
                    flag = AdaPayUtil.createCorpMember(subAccount, adaPayConfig, subAccountDTO.getFrontIdCardPhoto(), subAccountDTO.getReverseIdCardPhoto(), subAccountDTO.getOpenBankPermissionPhoto());
                } catch (BaseAdaPayException e) {
                    log.error(e.getMessage(), e);
                    subAccountDao.deleteById(subAccountId);
                    return Result.error("创建聚合支付企业用户失败");
                }
                if (!flag) {
                    subAccountDao.deleteById(subAccountId);
                    return Result.error("创建聚合支付企业用户失败");
                }
                break;
            case 2:
                try {
                    //对私，创建个人实名账户
                    flag = AdaPayUtil.creatMember(subAccount, adaPayConfig);
                } catch (BaseAdaPayException e) {
                    log.error(e.getMessage(), e);
                    subAccountDao.deleteById(subAccountId);
                    return Result.error("创建聚合支付个人用户失败");
                }
                if (!flag) {
                    //实名用户创建失败，删除记录
                    subAccountDao.deleteById(subAccountId);
                    return Result.error("实名认证不通过，请重新创建！");
                }
                try {
                    //创建结算账户
                    msg = AdaPayUtil.createSettleAccount(subAccount, adaPayConfig);
                } catch (BaseAdaPayException e) {
                    log.error(e.getMessage(), e);
                    subAccountDao.deleteById(subAccountId);
                    return Result.error("创建结算用户失败，请重新创建！");
                }
                if (!SubAccountConstant.SUCCESS_SETTLE_ACCOUNT.equals(msg)) {
                    subAccountDao.deleteById(subAccountId);
                    return Result.error(msg);
                }
                //结算账户创建成功,修改状态
                subAccountDao.updateState(subAccountId, SubAccountConstant.NORMAL);
                return Result.success();
            default:
                break;
        }
        return Result.success();
    }

    @Override
    public void updateMember(Integer subAccountId, String nickName, String autoRemark) {
        //autoRemark不能超过三十个汉字
        if (autoRemark != null && autoRemark.length() > 30) {
            throw new BaseException("自动提现备注长度不能超过三十个汉字");
        }
        subAccountDao.updateNickName(subAccountId, nickName, autoRemark);
    }

    @Override
    public Result deleteMember(Integer subAccountId) {
        //判断分账比例操作
        SubAccount subAccount = subAccountDao.selectById(subAccountId);
        //生效中的分账比例
        List<SubAccountRatio> subAccountRatioActiveList = subAccountDao.selectRatioCountByMemberIdAndState(subAccount.getMemberId(), SubAccountConstant.ACTIVE);
        if (subAccountRatioActiveList.size() > 0) {
            return Result.error("该账号有生效中的分账比例，删除失败");
        }
        //未生效的分账比例
        List<SubAccountRatio> subAccountRatioUnActiveList = subAccountDao.selectRatioCountByMemberIdAndState(subAccount.getMemberId(), SubAccountConstant.UN_ACTIVE);
        if (subAccountRatioUnActiveList.size() > 0) {
            return Result.error("该账号有未生效的分账比例，删除失败");
        }
        //判断如果账户有余额，不允许删除
        if (subAccount.getBalance() > 0) {
            return Result.error(String.format("该账户有%s元余额尚未提现，不允许删除", String.format("%.2f", ((double) subAccount.getBalance() / 100D))));
        }
        subAccountDao.updateState(subAccountId, SubAccountConstant.DELETE);
        return Result.success();
    }


    @Override
    public PageResult<SubAccount> queryPage(Integer accountId, Integer page, Integer size, Integer state, String nickName, String phone) {
        PageInfo<SubAccount> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> subAccountDao.selectByAccountIdAndState(accountId, state, nickName, phone));
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public Result bandAccountUser(SubAccountBind subAccountBind) {
        SubAccountBind subAccountBindInDB = subAccountDao.selectBand(subAccountBind);
        if (subAccountBindInDB != null) {
            return Result.error("绑定关系已存在，请勿重复绑定");
        }
        //查询用户已绑定的分账账户(只能绑定一个)
        SubAccountBind subAccountBindByAccountUserIdInDB = subAccountDao.selectBandByAccountUserId(subAccountBind.getAccountUserId());
        if (subAccountBindByAccountUserIdInDB != null) {
            return Result.error("该登录账号已有绑定，一个登录账号只能绑定一个分账账号");
        }
        //添加绑定关系
        subAccountDao.bandAccountUser(subAccountBind);
        return Result.success();
    }

    /**
     * 最大分账人数，adaPay那边最大为7，我们这边限制为最高6个
     */
    private static final int MAX_DIVIDE_NUMBER = 6;

    @Override
    //@Transactional(rollbackFor = Exception.class)
    public Result<Void> addSubAccountRatio(SubAccountRatioDTO dto, LoginInfo loginInfo) {
        // 校验参数
        checkRatio(dto);

        List<SubAccountRatio> addRatios = initInsertSubAccountRatio(dto, loginInfo);

        batchInsertRatioToDB(addRatios);
        return Result.success();
    }

    @Override
    @Transactional
    public Result<Void> batchAddMachineGroupRatio(List<SubAccountRatioDTO> dtoList, LoginInfo loginInfo) {
        // 校验参数
        List<Integer> groupIds = dtoList.stream()
                .map(SubAccountRatioDTO::getMachineGroupId)
                .filter(n -> n > 0)
                .collect(Collectors.toList());
        if (machineGroupService.getMachineGroupCountNotInIds(dtoList.get(0).getAdAccountId(), groupIds) > 0) {
            return Result.error("有分组未设置分账比例，请刷新后重试");
        }
        for (SubAccountRatioDTO dto : dtoList) {
            checkRatio(dto);
        }
        List<SubAccountRatio> addRatios = new ArrayList<>();
        for (SubAccountRatioDTO dto : dtoList) {
            addRatios.addAll(initInsertSubAccountRatio(dto, loginInfo));
        }
        batchInsertRatioToDB(addRatios);
        return Result.success();
    }

    private List<SubAccountRatio> initInsertSubAccountRatio(SubAccountRatioDTO dto, LoginInfo loginInfo) {
        List<SubAccountRatioDetailDTO> details = dto.getDetailDTO();
        Date now = new Date();

        //分组id
        String groupId = UUID.randomUUID().toString();
        List<SubAccountRatio> addRatios = new ArrayList<>();
        if (dto.getType() == SubAccountConstant.MACHINE_DIVIDE && dto.getMachineGroupId() == -1) {
            dto.setMachineGroupId(null);
        }
        for (int i = 0; i < details.size(); i++) {
            SubAccountRatioDetailDTO detail = details.get(i);
            SubAccount subAccount = subAccountDao.selectById(detail.getSubAccountId());
            Double ratio = detail.getProportion() / 100.0;
            //设置需要入库的信息
            SubAccountRatio subAccountRatio = new SubAccountRatio();
            subAccountRatio.setName(subAccount.getUserName())
                    .setAccountId(dto.getAdAccountId())
                    .setDivideType(dto.getType())
                    .setPhone(subAccount.getPhone())
                    .setUserNO(subAccount.getMemberId())
                    .setAddTime(now)
                    .setEffectiveTime(dto.getEffectTime())
                    .setState(SubAccountConstant.ACTIVE)
                    .setProportion(ratio)
                    .setMainUser(mainUserParse(SubAccountConstant.SLAVE_ACCOUNT))
                    .setAccountUserId(loginInfo.getAccountUserId())
                    .setMachineGroupId(dto.getMachineGroupId())
                    .setGroupId(groupId);
            //如果生效时间设置在当前时间之前的，就是立即生效的，把生效时间设置为当前时间
            if (subAccountRatio.getEffectiveTime().getTime() < now.getTime()) {
                subAccountRatio.setEffectiveTime(now);
            }
            //默认第一个为主账号
            if (0 == i) {
                subAccountRatio.setMainUser(mainUserParse(SubAccountConstant.MASTER_ACCOUNT));
            }
            addRatios.add(subAccountRatio);
        }
        return addRatios;
    }

    private void batchInsertRatioToDB(List<SubAccountRatio> ratios) {
        if (CollUtil.isEmpty(ratios)) {
            return;
        }
        //添加记录前把未生效的置为已过期
        subAccountDao.updateSubAccountRatioState(ratios.get(0).getAccountId(),
                SubAccountConstant.UN_ACTIVE, SubAccountConstant.ACTIVE_OVER,
                new Date(), ratios.get(0).getDivideType(), UUID.randomUUID().toString());

        // 未生效
        if (ratios.get(0).getEffectiveTime().after(new Date())) {
            ratios.forEach(subAccountRatio -> subAccountRatio.setState(SubAccountConstant.UN_ACTIVE));
        } else { // 立即生效
            //生效中的设为已过期
            subAccountDao.updateSubAccountRatioState(ratios.get(0).getAccountId(), SubAccountConstant.ACTIVE, SubAccountConstant.ACTIVE_OVER, new Date(), ratios.get(0).getDivideType(), UUID.randomUUID().toString());
        }
        //添加记录
        userDivideDao.insertBatch(ratios);

        //手动执行定时任务
//        subAccountQuartz.updateSubAccountRatioStateQuartz();
    }

    private void checkRatio(SubAccountRatioDTO dto) {
        List<SubAccountRatioDetailDTO> details = dto.getDetailDTO();
        if (details.size() > MAX_DIVIDE_NUMBER) {
            throw new BaseException("超出最大可分账人数，请重新设置");
        }

        Set<Integer> subAccountIds = details.stream()
                .map(SubAccountRatioDetailDTO::getSubAccountId)
                .collect(Collectors.toSet());
        if (subAccountIds.size() != details.size()) {
            throw new BaseException("不能选择多个相同的分账账户");
        }

        List<SubAccount> subAccounts = subAccountDao.selectList(Wrappers.lambdaQuery(SubAccount.class)
                .in(SubAccount::getSubAccountId, subAccountIds));
        if (subAccounts.size() != details.size()) {
            throw new BaseException("分账账户不存在");
        }
        List<String> abnormalSubAccountNames = subAccounts.stream()
                .filter(s -> !SubAccountConstant.NORMAL.equals(s.getState()))
                .map(SubAccount::getNickName)
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(abnormalSubAccountNames)) {
            throw new BaseException("分账账户[" + String.join(",", abnormalSubAccountNames) + "]已被删除或状态异常");
        }

        if (details.stream().anyMatch(d -> d.getProportion() == null || d.getProportion() <= 0)) {
            throw new BaseException("比例不能为空或小于等于零");
        }
        if (details.stream().mapToInt(SubAccountRatioDetailDTO::getProportion).sum() != 100) {
            throw new BaseException("分账比例总和必须等于100");
        }

        if (dto.getMachineGroupId() != null && dto.getMachineGroupId() != -1 && !machineGroupService.getBaseMapper().exists(Wrappers.lambdaQuery(MachineGroup.class)
                .eq(MachineGroup::getMachineGroupId, dto.getMachineGroupId()))) {
            throw new BaseException("车辆分组不存在");
        }

        SubAccountRatioDetailDTO master = details.get(0); // 主账号

        //查询该品牌的服务费账号,限制服务费账号不能进行分账
        BrandRemoteConfig brandRemoteConfig = new BrandRemoteConfig();
        brandRemoteConfig.setAccountId(subAccounts.get(0).getAccountId());
        brandRemoteConfig.setConfigType(BrandRemoteConfigConstant.ADAPAY_CASH_FUWU_FEE);
        List<BrandRemoteConfig> brandRemoteConfigs = brandRemoteConfigDao.selectBrandRemoteConfigList(brandRemoteConfig);
        if (CollUtil.isNotEmpty(brandRemoteConfigs)) {
            BrandRemoteConfig remoteConfig = brandRemoteConfigs.get(0);
            String paramKV = remoteConfig.getParamKV();
            String feeAccountNo = paramKV.substring(paramKV.indexOf("=") + 1, paramKV.lastIndexOf(";"));
            if (subAccounts.get(0).getMemberId().equals(feeAccountNo)) {
                throw new BaseException("服务费账号不能设置为分账账号");
            }
        }
    }

    @Override
    public Result<PageResult<SubAccountBandUserVO>> queryBandAccountUser(Integer subAccountId, Integer page, Integer size) {
        PageInfo<SubAccountBandUserVO> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> subAccountDao.queryBandAccountUser(subAccountId));
        return Result.success(new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList()));
    }

    @Override
    public Result deleteBand(Integer subAccountId, Integer accountUserId) {
        subAccountDao.deleteBand(subAccountId, accountUserId);
        return Result.success();
    }

    @Override
    public PageResult<SubAccountRatioVO> querySubAccountRatio(Integer page, Integer size, Integer accountId, Integer state, String groupId, Integer type) {
        PageInfo<SubAccountRatioVO> pageInfo = PageHelper.startPage(page, size)
                .doSelectPageInfo(() -> subAccountDao.querySubAccountRatio(accountId, state, groupId, type));

        pageInfo.getList().forEach(ratio -> {
            // 修复double比例精度问题：1会变成0.999
            ratio.setProportion(BigDecimal.valueOf(ratio.getProportion()).setScale(2, RoundingMode.HALF_UP).doubleValue());
        });

        // 填充车辆分组信息
        if (Objects.equals(SubAccountConstant.MACHINE_DIVIDE, type)) {
            List<Integer> machineGroupIds = pageInfo.getList().stream()
                    .map(SubAccountRatioVO::getMachineGroupId)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());

            if (CollUtil.isNotEmpty(machineGroupIds)) {
                Map<Integer, MachineGroupVo> machineGroups = machineGroupService.selectListWithCountByIds(accountId, machineGroupIds)
                        .stream()
                        .collect(Collectors.toMap(MachineGroupVo::getMachineGroupId, Function.identity()));
                pageInfo.getList().forEach(ratio -> {
                    MachineGroupVo machineGroup = machineGroups.get(ratio.getMachineGroupId());
                    if (machineGroup != null) {
                        ratio.setMachineGroupName(machineGroup.getGroupName());
                        ratio.setCarCount(machineGroup.getCount());
                    }
                });
            }
        }

        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public Result<Void> editSubAccountRatioState(Integer accountId, Integer type) {
        //取消未生效的分账比例
        subAccountDao.editSubAccountRatioState(accountId, type);
        return Result.success();
    }

    @Override
    public SubAccountBalanceVO queryBalance(Integer accountId, String phone) {
        //查询用户总人数和用户总余额
        SubAccountBalanceVO subAccountBalanceVO = subAccountDao.selectAdaPayBalanceTotal(accountId, phone);
        if (subAccountBalanceVO.getAdaPayBalanceTotal() == null) {
            subAccountBalanceVO.setAdaPayBalanceTotal(0L);
        }
        if (subAccountBalanceVO.getBalanceTotal() == null) {
            subAccountBalanceVO.setBalanceTotal(0L);
        }
        if (subAccountBalanceVO.getNotAdaPayBalanceTotal() == null) {
            subAccountBalanceVO.setNotAdaPayBalanceTotal(0L);
        }
        return subAccountBalanceVO;


    }

    @Override
    public PageResult<SubAccountUserBalanceVO> queryUserBalancePage(Integer page, Integer size, Integer accountId, String phone) {
        PageInfo<SubAccountUserBalanceVO> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> subAccountDao.queryUserBalance(accountId, phone));
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public PageResult<SubAccountWithdrawalVO> querySubAccountWithdrawal(Integer page, Integer size, Integer accountId) {
        //查询用户提现列表
        PageInfo<SubAccountWithdrawalVO> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> subAccountDao.querySubAccountWithdrawal(accountId));
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    //@Transactional(rollbackFor = Exception.class)
    public Result withdrawalBalance(Integer subAccountId, Integer money, LoginInfo loginInfo, String remark) {
        if (money < 0) {
            return Result.error("金额有误，请重新输入");
        }
        SubAccount subAccount = subAccountDao.selectById(subAccountId);
        if (subAccount == null) {
            return Result.error("账户户不存在");
        }
        //获取汇付款支付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getInfoByAccountId(subAccount.getAccountId());
        if (adaPayConfig == null) {
            //汇付支付配置有误
            return Result.error("汇付支付配置有误");
        }
        // 获取默认提现类型
        BrandRemoteConfig config = brandRemoteConfigService.getRemoteConfigByBrandIdAndConfigType(subAccount.getAccountId(), BrandRemoteConfigConstant.DEFAULT_CASH_TYPE);
        AdapayCashType defaultCashType = AdapayCashType.T1;
        if (config != null && config.getParamKV() != null) {
            defaultCashType = AdapayCashType.of(config.getParamKV());
        } else {
            log.warn("品牌{}未配置默认提现类型，使用缺省值：{}", loginInfo.getId(), defaultCashType);
        }
        //查询账户信息
        SubAccountWithdrawalVO subAccountWithdrawalVO = subAccountDao.querySubAccountWithdrawalBySubAccountId(subAccountId);
        //账户余额(单位分)
        Integer balance = subAccountWithdrawalVO.getBalance();
        //预留金额(单位元)
        Integer reserveMoney = subAccountWithdrawalVO.getReserveMoney();
        if (reserveMoney == null) {
            reserveMoney = 0;
        }
        if ((balance - (reserveMoney * 100)) < 0) {
            //余额减去预留金额不足
            return Result.error("预留金额大于余额，提现失败");
        }
        if ((balance - money) < (reserveMoney * 100)) {
            //提现后预留金额不足
            return Result.error("提现后金额小于预留金额，提现失败");
        }
        //提现请求订单号
        String withdrawalOrderNo = null;
        //分转为元,保留两位小数
        Double moneyYuanD = ((double) money / 100D);
        String moneyYuan = String.format("%.2f", moneyYuanD);
        try {
            AdaPayUtil.initConfig(adaPayConfig);
            withdrawalOrderNo = AdaPayUtil.withdrawal(subAccount, adaPayConfig, moneyYuan, defaultCashType, remark);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("提现失败");
        }
        if (StringUtils.isEmpty(withdrawalOrderNo)) {
            return Result.error("提现失败");
        }
        //修改分账账户余额
        subAccountDao.updateBalance(subAccountId, balance - money);
        //插入提现日志
        SubAccountWithdrawalLog subAccountWithdrawalLog = new SubAccountWithdrawalLog(withdrawalOrderNo, subAccount.getAccountId(), new Date(), loginInfo.getAccountUserId(), loginInfo.getPhone(), subAccountId, money, SubAccountConstant.WITHDRAWAL_ING, SubAccountConstant.WITHDRAWAL_TYPE_MANUAL, subAccount.getBankCardNumber(), remark);
        subAccountLogDao.insertSubAccountWithdrawalLog(subAccountWithdrawalLog);
        return Result.success();
    }

    @Override
    public Result balanceRefund(Integer userId, Integer accountId, Double refundMoney) {
        String url = OperaPswConstant.ACCOUNT_OPERA_PUSH_URL + ServiceUrlConstant.CLIENT_RETURN_MONEY;
        long date = System.currentTimeMillis();
        String param = "youqu";
        String sign = MD5PasswordUtil.MD5("TBIT" + date + param);
        Map<String, Object> paramMap = new HashMap<>(8);
        paramMap.put("userId", userId);
        paramMap.put("adAccountId", accountId);
        paramMap.put("money", refundMoney);
        paramMap.put("date", date);
        paramMap.put("param", param);
        paramMap.put("sign", sign);
        HttpResponse response = HttpRequest.get(url).form(paramMap).execute();
        log.info("=================余额退款===================");
        JSONObject jsonObject = JSON.parseObject(response.body());
        //已退款金额
        Object data = jsonObject.get("data");
        if (data == null) {
            data = "0";
        }
        log.info(JSON.toJSONString(jsonObject));
        if (Double.valueOf(data.toString()).equals(refundMoney)) {
            return Result.success();
        }
        log.error("余额退款失败，请求参数为:{}，返回参数为{}", JSON.toJSONString(paramMap), jsonObject.toJSONString());
        Object msg = jsonObject.get("msg");
        String resMsg = String.format("退款异常,实际退款金额为:%s元", String.format("%.2f", Double.parseDouble(data.toString()) / 100D));
        if (msg != null) {
            resMsg = resMsg + "," + msg.toString();
        }
        return Result.error(resMsg);
    }

    @Override
    public PageResult<SubAccountRatioGroupVO> querySubAccountGroupRatio(Integer page, Integer size, Integer accountId, Integer state, Integer type) {
        PageInfo<SubAccountRatioGroupVO> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> subAccountDao.querySubAccountGroupRatio(accountId, state, type));

        // 填充车辆分组信息
        List<Integer> machineGroupIds = pageInfo.getList().stream()
                .map(SubAccountRatioGroupVO::getMachineGroupId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (CollUtil.isNotEmpty(machineGroupIds)) {
            Map<Integer, MachineGroupVo> machineGroups = machineGroupService.selectListWithCountByIds(accountId, machineGroupIds)
                    .stream()
                    .collect(Collectors.toMap(MachineGroupVo::getMachineGroupId, Function.identity()));
            pageInfo.getList().forEach(ratio -> {
                if (ratio.getMachineGroupId() != null) {
                    MachineGroupVo machineGroup = machineGroups.get(ratio.getMachineGroupId());
                    if (machineGroup != null) {
                        ratio.setMachineGroupName(machineGroup.getGroupName());
                        ratio.setCarCount(machineGroup.getCount());
                    }
                }
            });
        }

        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public Result refreshBalance() {
        subAccountQuartz.querySubAccountBalanceQuartz();
        return Result.success();
    }

    @Override
    public Result updateMerchants(SubAccountMerchantsDTO subAccountMerchantsDTO) {
        extracted(subAccountMerchantsDTO);
        String memberId = subAccountMerchantsDTO.getMemberId();
        if (StringUtils.isEmpty(memberId) || !SubAccountConstant.MERCHANTS_MEMBER_ID.equals(memberId)) {
            return Result.error("只允许修改商户账户信息");
        }

        subAccountDao.updateMerchants(subAccountMerchantsDTO);
        return Result.success();
    }

    private static void extracted(SubAccountMerchantsDTO subAccountMerchantsDTO) {
        if (StrUtil.isNotEmpty(subAccountMerchantsDTO.getOpenBank()) && subAccountMerchantsDTO.getOpenBank().length() > 64){
            throw new BaseException("开户银行名称过长");
        }else if (StrUtil.isNotEmpty(subAccountMerchantsDTO.getBankCardNumber()) && subAccountMerchantsDTO.getBankCardNumber().length() > 64){
            throw new BaseException("银行卡号过长");
        }else if (StrUtil.isNotEmpty(subAccountMerchantsDTO.getUserName()) && subAccountMerchantsDTO.getUserName().length() > 64){
            throw new BaseException("用户名过长");
        }else if (StrUtil.isNotEmpty(subAccountMerchantsDTO.getCardNumber()) && subAccountMerchantsDTO.getCardNumber().length() > 64){
            throw new BaseException("证件号过长");
        }else if (StrUtil.isNotEmpty(subAccountMerchantsDTO.getNickName()) && subAccountMerchantsDTO.getNickName().length() > 64){
            throw new BaseException("昵称过长");
        }
    }


    /**
     * 参数校验
     *
     * @param subAccountDTO
     */
    public void check(SubAccountDTO subAccountDTO) {
        //对公对私都要校验的
        notNull(subAccountDTO.getAccountId(), "品牌id");
        notNull(subAccountDTO.getSubAccountType(), "账号类型");
        notNull(subAccountDTO.getBankAccountType(), "银行账号类型");
        notNull(subAccountDTO.getOpenBank(), "开户银行名称");
        notNull(subAccountDTO.getBankCardNumber(), "银行卡号");
        notNull(subAccountDTO.getCardType(), "证件类型");
        notNull(subAccountDTO.getCardNumber(), "证件号");
        notNull(subAccountDTO.getPhone(), "手机号");
        notNull(subAccountDTO.getNickName(), "昵称");
        switch (subAccountDTO.getBankAccountType()) {
            case 1:
                //对公需要校验的
                notNull(subAccountDTO.getBankCode(), "银行编码");
                notNull(subAccountDTO.getCompanyName(), "公司名称");
                notNull(subAccountDTO.getProvinceCode(), "省份编码");
                notNull(subAccountDTO.getAreaCode(), "地区编码");
                notNull(subAccountDTO.getCompanyCode(), "统一社会信用码");
                notNull(subAccountDTO.getCompanyCode(), "统一社会信用码");
                notNull(subAccountDTO.getCompanyCodeValidity(), "统一社会信用证有效期");
                notNull(subAccountDTO.getCardNumberValidity(), "法人身份证有效期");
                notNull(subAccountDTO.getBusinessScope(), "经营范围");
                notNull(subAccountDTO.getCompanyAddress(), "企业地址");
                notNull(subAccountDTO.getFrontIdCardPhoto(), "法人身份证正面照");
                notNull(subAccountDTO.getReverseIdCardPhoto(), "法人身份证反面照");
                notNull(subAccountDTO.getOpenBankPermissionPhoto(), "开户银行许可证照");
                break;
            case 2:
                break;
            default:
                throw new BaseException("银行账户类型有误");
        }
    }

    /**
     * 非空断言
     *
     * @param param  参数
     * @param remark 参数解析
     */
    public void notNull(Object param, String remark) {
        if (param == null || "".equals(param)) {
            throw new BaseException(String.format("%s不能为空", remark));
        }
    }


    /**
     * 账号类型解析
     *
     * @param subAccountType
     * @return
     */
    public Integer mainUserParse(Integer subAccountType) {
        switch (subAccountType) {
            case 0:
                return 1;
            case 1:
                return 0;
            default:
                return null;
        }
    }

    /**
     * 修改个人用户银行卡
     *
     * @param
     * @return
     */
    @Override
    public Result updateBankCard(Integer accountId, Integer subAccountId, String bankCardNumber, String openBank) {

        //获取汇付款支付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getInfoByAccountId(accountId);
        try {
            AdaPayUtil.initConfig(adaPayConfig);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("初始化配置失败，请检查汇付配置是否有误");
        }
        SubAccount subAccount = subAccountDao.selectById(subAccountId);
        String string;
        try {
            string = AdaPayUtil.updateBankCard(subAccount, adaPayConfig, bankCardNumber);
        } catch (BaseAdaPayException e) {
            return Result.error("修改银行卡失败" + e.getMessage());
        }
        if ("true".equals(string)) {
//            subAccountDao.updateBankCard(subAccount.getMemberId(),bankCardNumber,openBank);
            return Result.success();
        }
        return Result.error(string);
    }

    /**
     * 查询个人用户银行卡
     *
     * @param
     * @return
     */
    @Override
    public Result selectBankCard(Integer accountId, Integer subAccountId) {

        //获取汇付款支付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getInfoByAccountId(accountId);
        try {
            AdaPayUtil.initConfig(adaPayConfig);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("初始化配置失败，请检查汇付配置是否有误");
        }
        SubAccount subAccount = subAccountDao.selectById(subAccountId);
        String string;
        try {
            string = AdaPayUtil.selectBankCard(subAccount, adaPayConfig);
        } catch (BaseAdaPayException e) {
            return Result.error("修改银行卡失败" + e.getMessage());
        }
        return Result.success(string);
    }

    /**
     * 测试汇付提现记录
     * @return
     */
    @Override
    public Result getAdaPay() {
        try {
            //初始化
            Map<String, MerConfig> configMap = new HashMap<>();
            String key = String.format("%s-%s", 600389, "alipay_lite");
            MerConfig merConfig = new MerConfig();
            merConfig.setApiKey("api_live_bf760ea5-480e-4aa3-88b0-5965a0b55f4c");
            merConfig.setApiMockKey("api_test_98ed486c-4967-4484-8a02-431d038ba2a4");
            merConfig.setRSAPrivateKey("MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALqrls4QvKud6o4IE15bF0DWgYOYlhI0+/jfQZKpQS1MSpW7BwvcurdOv/Ry78v+pYvOJg+f1RlYdJBTSrVTeZWW5Dxl0JvF3HZbNTx6rBO94mcxxvD8mzoszSLw5wZST22Zn2U/DjrZrDmJ4dcqKoEESigOwrcKYTuv6eebRaV7AgMBAAECgYBRPWAyamJSJjXwfl8/j1E9bJ2NEhkt71VB6Jf3JiYxeqRzKaRVa0jvghxUXLk0BK0zfRJfdmYd07tXHIjFBYFB9COQa/VseRXtl24+6iLutqL4xiNPyG4M5OhJnsdwl1IkwgYTaZSaEtwl5q8okmt2NKC+g+WRPF8bKNhgfY56UQJBAO4K+fURMxO0yB8tMcHqoPQzyS8r5lMsArywdokJPFoVV0GVfj4MBvCHLbWYu5sJG3oNLtN929ikSVaXVDyPpO0CQQDIwISYJtI1KIAR9KI5pUaK1pl5/1Ej2BxSwF1JLbHawzuOEFoSwxcIRRT+qJP6g2v3NeP9WuPUTL0kdfsp308HAkEAhWCvF4qwlN0ZuKZJF/+QeeQ+WOj/ICEr03AIqtX68/q7LmtGFhwFE2aazQKsM71RoPyb/TKrKWM8GIGoWFqgLQJAUzL+gPRt4BwV39ssNInbz4Sa/OWkoh9Zta4Fu2NVt518HCeIvQffjszao6QIGCXJZB4QjBrUG1NmfCrtWfAzlwJBAJ1AeZBnOMEh/Wt/BEtkQr5wE7QpJeWn7zJPo/eey9tC63rFGInGqFxk6c2Oj9uZlbVLW1KRzKIJ3eaxTDqiR/g=");
            configMap.put(key, merConfig);

            Adapay.initWithMerConfigs(configMap);

            Map<String, Object> queryParams = new HashMap<String, Object>(5);
            queryParams.put("member_id", "uqbikeSubAccount_600389_179_1734332251416");
            queryParams.put("app_id", "app_6335c5a0-282b-488b-adda-faba5e57c961");
            queryParams.put("begin_date", "20250201");
            queryParams.put("end_date", "20250221");
            Map<String, Object> settleCount = SettleAccount.detail(queryParams, key);
            log.info("提现历史:{}", settleCount);
            JSONArray settleDetails = JSON.parseArray(settleCount.get("settle_details").toString());
            for (Object settleDetail : settleDetails) {
                JSONObject jsonObject = JSON.parseObject(settleDetail.toString());

                Integer schedule = null;
                String settleStat = jsonObject.getString("settle_stat");
                if ("succeeded".equals(settleStat)){
                    schedule = 2;
                }else if ("failed".equals(settleStat)){
                    schedule = 3;
                }else if ("pending".equals(settleStat)){
                    schedule = 1;
                }

                String sql = String.format("insert into subaccountwithdrawallog(withdrawalOrderNO,accountId,addTime,subAccountId,withdrawalMoney,`schedule`,withdrawalType,bankCardNumber,remark) " +
                        "values('%s', 267, '2025-02-21 15:25:00', 227, %s, %s, 2, '%s', '%s');",UUID.randomUUID(), jsonObject.getDouble("settle_amt"), schedule, jsonObject.getString("card_no"), jsonObject.getString("settle_type"));
                System.out.println(sql);
            }

        } catch (Exception e) {
            log.error("获取配置失败", e);
        }

        return Result.success();
    }

    void checkLength(SubAccountDTO subAccountDTO){
        if (StrUtil.isNotEmpty(subAccountDTO.getOpenBank()) && subAccountDTO.getOpenBank().length() > 64){
            throw new BaseException("开户银行名称过长");
        }else if (StrUtil.isNotEmpty(subAccountDTO.getBankCardNumber()) && subAccountDTO.getBankCardNumber().length() > 64){
            throw new BaseException("银行卡号过长");
        }else if (StrUtil.isNotEmpty(subAccountDTO.getUserName()) && subAccountDTO.getUserName().length() > 64){
            throw new BaseException("用户名过长");
        }else if (StrUtil.isNotEmpty(subAccountDTO.getCardNumber()) && subAccountDTO.getCardNumber().length() > 64){
            throw new BaseException("证件号过长");
        }else if (StrUtil.isNotEmpty(subAccountDTO.getNickName()) && subAccountDTO.getNickName().length() > 64){
            throw new BaseException("昵称过长");
        }else if (StrUtil.isNotEmpty(subAccountDTO.getPhone()) && subAccountDTO.getPhone().length() > 64){
            throw new BaseException("手机号过长");
        }
    }

}
